#include <aos/aos.h>
#include <string.h>

#include "hal/soc/uart.h"
#include "smart_outlet.h"

extern uart_dev_t uart_1;

#define RECV_TIMEOUT 100
#define SEND_TIMEOUT 50
#define MAX_DATA_LEN 512
#define BYTE_0       0x5a
#define BYTE_1       0xa5

static uint8_t dataCheckSum(uint8_t *data, uint32_t len);
static int     uartSend(uint8_t *data, uint32_t size, uint32_t timeout);
static int     uartRecv(uint8_t *data, uint32_t len, uint32_t timeout);
static int     uartRecvDataProcess(uint8_t *data, uint32_t len);

// head  0      1       2       3       4       5           6       7       8
//       ver    id      type    total   total   total&idx   idx     idx     len
int uartSend(uint8_t *data, uint32_t len, uint32_t timeout)
{
    int ret = 0;

    ret = hal_uart_send(&uart_1, &data[0], len, timeout);
    if (ret != 0) {
        app_err("uart write Failed !!!");
    }
    return ret;
}

int uartRecv(uint8_t *data, uint32_t len, uint32_t timeout)
{
    uint32_t retlen    = 0;
    uint32_t readtotal = 0, expectlen = len;

    do {
        hal_uart_recv_II(&uart_1, (void *)&data[readtotal], expectlen, &retlen, timeout);
        if (retlen > 0 && (uint32_t)retlen <= len) {
            expectlen -= retlen;
            readtotal += retlen;
        } else {
            app_err("uart Recv Failed\r\n");
            app_err("uart Read len %d  %d %d %d!!!", retlen, len, expectlen, readtotal);
        }
    } while (retlen > 0 && readtotal != len);
    if (readtotal != len) {
        app_err("uart Read Failed !!!");
    }
    return readtotal;
}

static void hex_data_dump(const char *string, uint8_t *pdata, uint32_t length)
{
    uint32_t i = 0;

    printf("%s %lu bytes:", string, length);
    for (i = 0; i < length; i++) {
        if (0 == i % 16) {
            printf("\r\n");
        }
        printf("%02X ", pdata[i]);
    }
    printf("\r\n");
}

static void _uart_recv_task(void *arg)
{
    uint8_t  read_buf[MAX_DATA_LEN] = {0};
    uint32_t real_len               = 0;
    app_info("start _uart_recv_task");

    while (1) {
        real_len = 0;
        memset(read_buf, 0, MAX_DATA_LEN);
        hal_uart_recv_II(&uart_1, &read_buf[0], 1, &real_len, RECV_TIMEOUT);
        if (real_len != 1 || read_buf[0] != BYTE_0) {
            // app_info("recv0: %02x", read_buf[0]);
            continue;
        }
        hal_uart_recv_II(&uart_1, &read_buf[1], 1, &real_len, RECV_TIMEOUT);
        if (real_len != 1 || read_buf[1] != BYTE_1) {
            app_info("recv1: %02x", read_buf[0]);
            continue;
        }
        hal_uart_recv_II(&uart_1, &read_buf[2], 2, &real_len, RECV_TIMEOUT / 2);
        if (real_len != 2) {
            app_info("uart fail len=%d", real_len);
            continue;
        }
        uint16_t len = read_buf[2] << 8 | read_buf[3];
        app_info("data len %d", len);
        hex_data_dump("Head info", read_buf, 4);
        if (len > MAX_DATA_LEN) {
            app_err("data length is invaliable len %d!!!", len);
        } else {
            int ret = hal_uart_recv_II(&uart_1, &read_buf[4], len + 1, &real_len, RECV_TIMEOUT);
            if (real_len != len + 1) {
                app_err("recv data len error %d %d ret %d!!!", len + 1, real_len, ret);
            } else {
                uartRecvDataProcess(read_buf, len + 5);
            }
        }
    }
}

static uint8_t data_buff[] = {0x5a, 0xa5, 0x00, 0x04, 0x31, 0x32, 0x33, 0x34, 0xcd};

static void _uart_send_task(void *arg)
{
    app_info("start _uart_send_task");

    while (1) {
        hal_uart_send(&uart_1, &data_buff[0], sizeof(data_buff), SEND_TIMEOUT);
        aos_msleep(500);
    }
}

int uartRecvDataProcess(uint8_t *data, uint32_t len)
{
    int ret = 0;
    hex_data_dump("recv data", data, len);

    int sum = dataCheckSum(data, len - 1);
    if (sum != data[len - 1])
        app_err("recv data error sum %02x %02x !!!", sum, data[len - 1]);
    else
        app_err("recv success !!!");

    return ret;
}

uint8_t dataCheckSum(uint8_t *data, uint32_t len)
{
    int8_t value = 0x00;

    for (uint32_t i = 0; i < len; i++) {
        value += (data[i] & 0xff);
    }

    return value;
}

#define BAUD_SPEED 921600
extern void       uart1_rbuf_init(uint32_t baud_rate);
static aos_task_t uart_send_task_handle, uart_recv_task_handle;

void aiot_uart_init(void)
{
    uart1_rbuf_init(BAUD_SPEED);

    aos_task_new_ext(&uart_recv_task_handle, "uart recv task", _uart_recv_task, NULL, 2048, AOS_DEFAULT_APP_PRI - 1);
    aos_task_new_ext(&uart_send_task_handle, "uart send task", _uart_send_task, NULL, 2048, AOS_DEFAULT_APP_PRI - 1);
}
